function Promise.prototype._unwrap(U)if U._status==Promise.Status.Started then error("\080\114\111\109\105\115\101 \104\097\115 \110\111\116 \114\101\115\111\108\118\101\100 \111\114 \114\101\106\101\099\116\101\100\046",2)end local Z=U._status==Promise.Status.Resolved return Z,unpack(U._values,1,U._valuesLength)end function Promise.prototype._resolve(U,...)if U._status~=Promise.Status.Started then if Promise.is(...)then(...):_consumerCancelled(U)end return end if Promise.is(...)then if select("\035",...)>1 then local Z=string.format("\087\104\101\110 \114\101\116\117\114\110\105\110\103 \097 \080\114\111\109\105\115\101 \102\114\111\109 \097\110\100\084\104\101\110\044 \101\120\116\114\097 \097\114\103\117\109\101\110\116\115 \097\114\101 \100\105\115\099\097\114\100\101\100\033 \083\101\101\058\n\n\037\115",U._source)warn(Z)end local Z=...local f=Z:andThen(function(...)U:_resolve(...)end,function(...)local f=Z._values[1]if Z._error then f=Error.new({error=Z._error;kind=Error.Kind.ExecutionError;context="\091\078\111 \115\116\097\099\107 \116\114\097\099\101 \097\118\097\105\108\097\098\108\101 \097\115 \116\104\105\115 \080\114\111\109\105\115\101 \111\114\105\103\105\110\097\116\101\100 \102\114\111\109 \097\110 \111\108\100\101\114 \118\101\114\115\105\111\110 \111\102 \116\104\101 \080\114\111\109\105\115\101 \108\105\098\114\097\114\121 \040\060 \118\050\041\093"})end if Error.isKind(f,Error.Kind.ExecutionError)then return U:_reject(f:extend({error="\084\104\105\115 \080\114\111\109\105\115\101 \119\097\115 \099\104\097\105\110\101\100 \116\111 \097 \080\114\111\109\105\115\101 \116\104\097\116 \101\114\114\111\114\101\100\046",trace="";context=string.format("\084\104\101 \080\114\111\109\105\115\101 \097\116\058\n\n\037\115\n\046\046\046\082\101\106\101\099\116\101\100 \098\101\099\097\117\115\101 \105\116 \119\097\115 \099\104\097\105\110\101\100 \116\111 \116\104\101 \102\111\108\108\111\119\105\110\103 \080\114\111\109\105\115\101\044 \119\104\105\099\104 \101\110\099\111\117\110\116\101\114\101\100 \097\110 \101\114\114\111\114\058\n",U._source)}))end U:_reject(...)end)if f._status==Promise.Status.Cancelled then U:cancel()elseif f._status==Promise.Status.Started then U._parent=f f._consumers[U]=true end return end U._status=Promise.Status.Resolved U._valuesLength,U._values=pack(...)for U,Z in ipairs(U._queuedResolve)do(coroutine.wrap(Z))(...)end U:_finalize()end function Promise.prototype._reject(U,...)if U._status~=Promise.Status.Started then return end U._status=Promise.Status.Rejected U._valuesLength,U._values=pack(...)if not isEmpty(U._queuedReject)then for U,Z in ipairs(U._queuedReject)do(coroutine.wrap(Z))(...)end else local Z=tostring(...);(coroutine.wrap(function()Promise._timeEvent:Wait()if not U._unhandledRejection then return end local f=string.format("\085\110\104\097\110\100\108\101\100 \080\114\111\109\105\115\101 \114\101\106\101\099\116\105\111\110\058\n\n\037\115\n\n\037\115",Z,U._source)if Promise.TEST then return end end))()end U:_finalize()end
--[[
	Intended for use in tests.

	Similar to await(), but instead of yielding if the promise is unresolved,
	_unwrap will throw. This indicates an assumption that a promise has
	resolved.
]]
function Promise.prototype:_unwrap()
	if self._status == Promise.Status.Started then
		error("Promise has not resolved or rejected.", 2)
	end

	local success = self._status == Promise.Status.Resolved

	return success, unpack(self._values, 1, self._valuesLength)
end

function Promise.prototype:_resolve(...)
	if self._status ~= Promise.Status.Started then
		if Promise.is((...)) then
			(...):_consumerCancelled(self)
		end
		return
	end

	-- If the resolved value was a Promise, we chain onto it!
	if Promise.is((...)) then
		-- Without this warning, arguments sometimes mysteriously disappear
		if select("#", ...) > 1 then
			local message = string.format(
				"When returning a Promise from andThen, extra arguments are " .. "discarded! See:\n\n%s",
				self._source
			)
			warn(message)
		end

		local chainedPromise = ...

		local promise = chainedPromise:andThen(function(...)
			self:_resolve(...)
		end, function(...)
			local maybeRuntimeError = chainedPromise._values[1]

			-- Backwards compatibility < v2
			if chainedPromise._error then
				maybeRuntimeError = Error.new({
					error = chainedPromise._error,
					kind = Error.Kind.ExecutionError,
					context = "[No stack trace available as this Promise originated from an older version of the Promise library (< v2)]",
				})
			end

			if Error.isKind(maybeRuntimeError, Error.Kind.ExecutionError) then
				return self:_reject(maybeRuntimeError:extend({
					error = "This Promise was chained to a Promise that errored.",
					trace = "",
					context = string.format(
						"The Promise at:\n\n%s\n...Rejected because it was chained to the following Promise, which encountered an error:\n",
						self._source
					),
				}))
			end

			self:_reject(...)
		end)

		if promise._status == Promise.Status.Cancelled then
			self:cancel()
		elseif promise._status == Promise.Status.Started then
			-- Adopt ourselves into promise for cancellation propagation.
			self._parent = promise
			promise._consumers[self] = true
		end

		return
	end

	self._status = Promise.Status.Resolved
	self._valuesLength, self._values = pack(...)

	-- We assume that these callbacks will not throw errors.
	for _, callback in ipairs(self._queuedResolve) do
		coroutine.wrap(callback)(...)
	end

	self:_finalize()
end

function Promise.prototype:_reject(...)
	if self._status ~= Promise.Status.Started then
		return
	end

	self._status = Promise.Status.Rejected
	self._valuesLength, self._values = pack(...)

	-- If there are any rejection handlers, call those!
	if not isEmpty(self._queuedReject) then
		-- We assume that these callbacks will not throw errors.
		for _, callback in ipairs(self._queuedReject) do
			coroutine.wrap(callback)(...)
		end
	else
		-- At this point, no one was able to observe the error.
		-- An error handler might still be attached if the error occurred
		-- synchronously. We'll wait one tick, and if there are still no
		-- observers, then we should put a message in the console.

		local err = tostring((...))

		coroutine.wrap(function()
			Promise._timeEvent:Wait()

			-- Someone observed the error, hooray!
			if not self._unhandledRejection then
				return
			end

			-- Build a reasonable message
			local message = string.format("Unhandled Promise rejection:\n\n%s\n\n%s", err, self._source)

			if Promise.TEST then
				-- Don't spam output when we're running tests.
				return
			end
		end)()
	end

	self:_finalize()
end
